Skip to content

GTM consent mode#955

Merged
maureenlholland merged 4 commits intomainfrom
wt-602--consent-management
Mar 3, 2026
Merged

GTM consent mode#955
maureenlholland merged 4 commits intomainfrom
wt-602--consent-management

Conversation

@maureenlholland
Copy link
Collaborator

@maureenlholland maureenlholland commented Feb 4, 2026

One-line summary

GTM implementation of Google consent mode: https://developers.google.com/tag-platform/security/guides/consent?consentmode=advanced#tag-manager_2

Default

  • if on /landing/get with no user pref and no consent required, allow analytics
  • if user pref, use user pref
  • else denial

Update

  • both ad and analytics consent will update according to pref

Significant changes and points to review

Issue / Bugzilla link

https://mozilla-hub.atlassian.net/browse/WT-602

Testing

Available on Demo 3:

When GTM is loaded on most pages:

  • and there is no existing analytics cookie, defaults are denied
  • and there is an existing analytics cookie TRUE, defaults are granted

When GTM is loaded on /landing/get

  • and there is no existing analytics cookie and consent is not required, analytics default is granted, ad defaults are denied
Screenshot 2026-02-11 at 6 49 17 PM

When user indicates pref, an 'update' dataLayer event appears:

Screenshot 2026-02-11 at 6 50 19 PM

Google verification docs: https://developers.google.com/tag-platform/security/guides/consent-debugging#start-debugging

@maureenlholland maureenlholland force-pushed the wt-602--consent-management branch from b333a17 to 31fb40b Compare February 11, 2026 11:49
@maureenlholland maureenlholland changed the title wip GTM consent mode Feb 11, 2026
@codecov
Copy link

codecov bot commented Feb 11, 2026

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 77.27%. Comparing base (7cc7ebf) to head (5acda8f).
⚠️ Report is 34 commits behind head on main.

Additional details and impacted files
@@            Coverage Diff             @@
##             main     #955      +/-   ##
==========================================
+ Coverage   76.47%   77.27%   +0.80%     
==========================================
  Files         124      124              
  Lines        7599     7627      +28     
==========================================
+ Hits         5811     5894      +83     
+ Misses       1788     1733      -55     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@maureenlholland maureenlholland force-pushed the wt-602--consent-management branch 4 times, most recently from 6e88cec to 4bb0767 Compare February 16, 2026 18:47
@maureenlholland maureenlholland marked this pull request as ready for review February 17, 2026 09:42
@maureenlholland
Copy link
Collaborator Author

maureenlholland commented Feb 17, 2026

Needs automated tests once behaviour is confirmed (edit: this can be a follow-up task as long as demo behaviour is approved)

@maureenlholland maureenlholland force-pushed the wt-602--consent-management branch 2 times, most recently from 19070e8 to 2661092 Compare February 18, 2026 12:09
@stevejalim stevejalim force-pushed the wt-602--consent-management branch from 2661092 to d86eac6 Compare February 25, 2026 11:27

if (hasPref) {
setGtagAdsConsentMode(cookie.analytics, 'default');
setGtagAnalyticsConsentMode(cookie.analytics);
Copy link

@stephendherrera stephendherrera Feb 25, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

QA Bug: During testing, analytics_storage was observed firing as "update" instead of "default" when a moz-consent-pref cookie exists. This means analytics has no declared default state before GTM loads. Google falls back to its own implicit default until the update arrives.

The type argument is missing here, so it defaults to 'update'. It should be 'default' to match the ads consent call on the line above:

setGtagAnalyticsConsentMode(cookie.analytics, 'default');

Google's consent mode requires default to be set before GTM loads. Confirmed inspection on demo3 shows "1": "update" instead of "1": "default" on page load when a cookie is present (tested on /firefox/new/ and /landing/get?geo=FR).

@stephendherrera
Copy link

@maureenlholland Overall, 99% there, one itemg observed, left an inline comment.

Tested on demo3. All GTM loading gates pass (DNT, GPC, consent-required geo). The /landing/get special rule works correctly, analytics granted, ads denied with no cookie.

GTM Loading Gates

  1. DNT enabled == PASS
  2. GPC enabled == PASS
  3. /landing/get?geo=FR no consent == PASS
  4. A4 No gates active == PASS

Consent Defaults

  1. No cookie -> all denied == PASS
  2. Cookie analytics: true == FAIL analytics_storage fires as update instead of default
  3. Cookie analytics: false == Pass, GTM doesn't load

Consent Defaults (/landing/get)

  1. No cookie, no consent required -> analytics granted, ads denied == PASS
  2. ?geo=FR, no consent -> GTM doesn't load == PASS
  3. Cookie analytics: true on ?geo=FR -> all granted == PASS

Update Events

  1. Uncheck marketing opt-out -> update fires, all denied == PASS
  2. Accept consent banner on ?geo=FR -> update fires, all granted == PASS
  3. Cookie settings page, select No -> update fires, all denied == PASS

GTMSnippet.handleConsent = (e) => {
const hasConsent = e.detail.analytics;

// update gtag consent according to pref
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is probably a bit redundant given the consent rules under which we display the consent banner (denial default is likely in place & we may be updating for denial too), but it feels more future-proof in case the consent banner logic changes

Copy link

@stephendherrera stephendherrera left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

QA verified on demo3. Missing default type on setGtagAnalyticsConsentMode is confirmed working. analytics_storage correctly fires as default instead of update when a consent cookie is present on page load.

My tests below:

No cookie==all denied defaults
Cookie analytics:true==all granted as default
/landing/get no cookie, no consent required==analytics granted, ads denied
Consent banner accept on ?geo=FR ==GTM loads with correct grants
DNT/GPC gates and cookie settings paths were not re-tested as recent changes don't affect those paths.

@maureenlholland maureenlholland merged commit b49a8a9 into main Mar 3, 2026
6 checks passed
@maureenlholland maureenlholland deleted the wt-602--consent-management branch March 3, 2026 10:49
slightlyoffbeat added a commit that referenced this pull request Mar 9, 2026
PR #955 introduced Google Consent Mode defaults that inadvertently set analytics_storage to 'denied' for all pages except /landing/get. This silently blocked GA4 from recording events for the majority of site traffic — visitors outside EU/EAA without a consent cookie.

  The fix replaces the /landing/get-specific check with a region-based
  check, so analytics_storage defaults to 'granted' whenever explicit
  consent is not required, matching the existing GTM loading behavior
  in init().
maureenlholland added a commit that referenced this pull request Mar 10, 2026
* fix:  fix: default analytics_storage

PR #955 introduced Google Consent Mode defaults that inadvertently set analytics_storage to 'denied' for all pages except /landing/get. This silently blocked GA4 from recording events for the majority of site traffic — visitors outside EU/EAA without a consent cookie.

  The fix replaces the /landing/get-specific check with a region-based
  check, so analytics_storage defaults to 'granted' whenever explicit
  consent is not required, matching the existing GTM loading behavior
  in init().

* grant ad_storage default on /landing/get for non-EU visitors

Matches the marketing opt-out checkbox state upfront so there is
  no gap between GTM loading with ads denied and a later update.

* Update tests/unit/spec/base/gtm/gtm-snippet.js

Co-authored-by: maureenlholland <[email protected]>

* Update tests/unit/spec/base/gtm/gtm-snippet.js

Co-authored-by: maureenlholland <[email protected]>

---------

Co-authored-by: Steve Jalim <[email protected]>
Co-authored-by: maureenlholland <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants